/**
 * Sub-Agents System Tests
 * 
 * Tests for SubAgentManager, builtin sub-agents, and API endpoints
 */

import { describe, test, expect, beforeEach } from 'bun:test';
import { SubAgentManager } from '@/subagents/subagent-manager';
import { getBuiltinSubAgents } from '@/subagents/builtin';
import type { SubAgentConfig } from '@/types';

describe('SubAgentManager', () => {
  let manager: SubAgentManager;

  beforeEach(() => {
    manager = new SubAgentManager();
  });

  describe('Registration', () => {
    test('should register a new sub-agent', () => {
      const config: SubAgentConfig = {
        id: 'test-agent',
        name: 'Test Agent',
        description: 'A test sub-agent',
        prompt: 'You are a test agent.',
        model: 'sonnet',
        category: 'testing',
      };

      manager.registerSubAgent(config);
      const agent = manager.getSubAgent('test-agent');
      
      expect(agent).toBeDefined();
      expect(agent?.name).toBe('Test Agent');
      expect(agent?.model).toBe('sonnet');
    });

    test('should overwrite existing sub-agent when registering with same id', () => {
      const config1: SubAgentConfig = {
        id: 'test-agent',
        name: 'Test Agent 1',
        description: 'First version',
        prompt: 'Version 1',
      };

      const config2: SubAgentConfig = {
        id: 'test-agent',
        name: 'Test Agent 2',
        description: 'Second version',
        prompt: 'Version 2',
      };

      manager.registerSubAgent(config1);
      manager.registerSubAgent(config2);
      
      const agent = manager.getSubAgent('test-agent');
      expect(agent?.name).toBe('Test Agent 2');
      expect(agent?.prompt).toBe('Version 2');
    });

    test('should register multiple sub-agents', () => {
      const configs: SubAgentConfig[] = [
        { id: 'agent-1', name: 'Agent 1', description: 'First', prompt: 'Prompt 1' },
        { id: 'agent-2', name: 'Agent 2', description: 'Second', prompt: 'Prompt 2' },
        { id: 'agent-3', name: 'Agent 3', description: 'Third', prompt: 'Prompt 3' },
      ];

      configs.forEach(config => manager.registerSubAgent(config));
      
      const allAgents = manager.getAllSubAgents();
      expect(allAgents.length).toBe(3);
    });
  });

  describe('Retrieval', () => {
    beforeEach(() => {
      manager.registerSubAgent({
        id: 'test-agent',
        name: 'Test Agent',
        description: 'A test sub-agent',
        prompt: 'You are a test agent.',
      });
    });

    test('should get sub-agent by id', () => {
      const agent = manager.getSubAgent('test-agent');
      expect(agent).toBeDefined();
      expect(agent?.id).toBe('test-agent');
    });

    test('should return undefined for non-existent sub-agent', () => {
      const agent = manager.getSubAgent('non-existent');
      expect(agent).toBeUndefined();
    });

    test('should get all sub-agents', () => {
      manager.registerSubAgent({
        id: 'agent-2',
        name: 'Agent 2',
        description: 'Second agent',
        prompt: 'Prompt 2',
      });

      const allAgents = manager.getAllSubAgents();
      expect(allAgents.length).toBe(2);
    });
  });

  describe('Update', () => {
    beforeEach(() => {
      manager.registerSubAgent({
        id: 'test-agent',
        name: 'Test Agent',
        description: 'Original description',
        prompt: 'Original prompt',
        model: 'sonnet',
      });
    });

    test('should update sub-agent properties', () => {
      const updated = manager.updateSubAgent('test-agent', {
        name: 'Updated Agent',
        description: 'Updated description',
      });

      expect(updated).toBe(true);
      
      const agent = manager.getSubAgent('test-agent');
      expect(agent?.name).toBe('Updated Agent');
      expect(agent?.description).toBe('Updated description');
      expect(agent?.prompt).toBe('Original prompt'); // Unchanged
    });

    test('should return false when updating non-existent sub-agent', () => {
      const updated = manager.updateSubAgent('non-existent', {
        name: 'Updated',
      });

      expect(updated).toBe(false);
    });
  });

  describe('Deletion', () => {
    beforeEach(() => {
      manager.registerSubAgent({
        id: 'test-agent',
        name: 'Test Agent',
        description: 'A test sub-agent',
        prompt: 'You are a test agent.',
      });
    });

    test('should remove sub-agent', () => {
      const removed = manager.removeSubAgent('test-agent');
      expect(removed).toBe(true);
      
      const agent = manager.getSubAgent('test-agent');
      expect(agent).toBeUndefined();
    });

    test('should return false when removing non-existent sub-agent', () => {
      const removed = manager.removeSubAgent('non-existent');
      expect(removed).toBe(false);
    });

    test('should not remove builtin sub-agents', () => {
      manager.registerSubAgent({
        id: 'builtin-agent',
        name: 'Builtin Agent',
        description: 'A builtin sub-agent',
        prompt: 'You are builtin.',
        isBuiltin: true,
      });

      const removed = manager.removeSubAgent('builtin-agent');
      expect(removed).toBe(false);
      
      const agent = manager.getSubAgent('builtin-agent');
      expect(agent).toBeDefined();
    });
  });

  describe('SDK Configuration', () => {
    test('should generate SDK agents config', () => {
      manager.registerSubAgent({
        id: 'test-agent',
        name: 'Test Agent',
        description: 'When you need to test something',
        prompt: 'You are a test agent.',
        tools: ['Read', 'Write'],
        model: 'sonnet',
      });

      const sdkConfig = manager.getAgentsConfig();
      
      expect(sdkConfig).toBeDefined();
      expect(sdkConfig['test-agent']).toBeDefined();
      expect(sdkConfig['test-agent'].description).toBe('When you need to test something');
      expect(sdkConfig['test-agent'].prompt).toBe('You are a test agent.');
      expect(sdkConfig['test-agent'].tools).toEqual(['Read', 'Write']);
      expect(sdkConfig['test-agent'].model).toBe('sonnet');
    });

    test('should exclude tools if not specified', () => {
      manager.registerSubAgent({
        id: 'test-agent',
        name: 'Test Agent',
        description: 'Test description',
        prompt: 'Test prompt',
      });

      const sdkConfig = manager.getAgentsConfig();
      expect(sdkConfig['test-agent'].tools).toBeUndefined();
    });
  });

  describe('Statistics', () => {
    test('should return correct statistics', () => {
      manager.registerSubAgent({
        id: 'custom-1',
        name: 'Custom 1',
        description: 'Custom agent',
        prompt: 'Prompt',
        category: 'development',
      });

      manager.registerSubAgent({
        id: 'builtin-1',
        name: 'Builtin 1',
        description: 'Builtin agent',
        prompt: 'Prompt',
        category: 'testing',
        isBuiltin: true,
      });

      const stats = manager.getStats();
      
      expect(stats.total).toBe(2);
      expect(stats.builtin).toBe(1);
      expect(stats.custom).toBe(1);
      expect(stats.byCategory.development).toBe(1);
      expect(stats.byCategory.testing).toBe(1);
    });
  });

  describe('Import/Export', () => {
    test('should export configuration', () => {
      manager.registerSubAgent({
        id: 'agent-1',
        name: 'Agent 1',
        description: 'First agent',
        prompt: 'Prompt 1',
      });

      const exported = manager.exportConfig();
      
      expect(exported).toBeArray();
      expect(exported.length).toBe(1);
      expect(exported[0].id).toBe('agent-1');
    });

    test('should import configuration', () => {
      const configs: SubAgentConfig[] = [
        { id: 'agent-1', name: 'Agent 1', description: 'First', prompt: 'Prompt 1' },
        { id: 'agent-2', name: 'Agent 2', description: 'Second', prompt: 'Prompt 2' },
      ];

      manager.importConfig(configs);
      
      const allAgents = manager.getAllSubAgents();
      expect(allAgents.length).toBe(2);
    });

    test('should not overwrite existing agents by default', () => {
      manager.registerSubAgent({
        id: 'agent-1',
        name: 'Original',
        description: 'Original description',
        prompt: 'Original prompt',
      });

      const configs: SubAgentConfig[] = [
        { id: 'agent-1', name: 'Imported', description: 'Imported description', prompt: 'Imported prompt' },
      ];

      manager.importConfig(configs, false);
      
      const agent = manager.getSubAgent('agent-1');
      expect(agent?.name).toBe('Original');
    });

    test('should overwrite existing agents when specified', () => {
      manager.registerSubAgent({
        id: 'agent-1',
        name: 'Original',
        description: 'Original description',
        prompt: 'Original prompt',
      });

      const configs: SubAgentConfig[] = [
        { id: 'agent-1', name: 'Imported', description: 'Imported description', prompt: 'Imported prompt' },
      ];

      manager.importConfig(configs, true);
      
      const agent = manager.getSubAgent('agent-1');
      expect(agent?.name).toBe('Imported');
    });
  });
});

describe('Builtin Sub-Agents', () => {
  test('should have 8 builtin sub-agents', () => {
    const builtins = getBuiltinSubAgents();
    expect(builtins.length).toBe(8);
  });

  test('should have all required builtin sub-agents', () => {
    const builtins = getBuiltinSubAgents();
    const ids = builtins.map(a => a.id);
    
    expect(ids).toContain('code-reviewer');
    expect(ids).toContain('test-writer');
    expect(ids).toContain('performance-optimizer');
    expect(ids).toContain('security-auditor');
    expect(ids).toContain('documentation-writer');
    expect(ids).toContain('refactoring-specialist');
    expect(ids).toContain('api-designer');
    expect(ids).toContain('database-specialist');
  });

  test('all builtin sub-agents should have required fields', () => {
    const builtins = getBuiltinSubAgents();
    
    builtins.forEach(agent => {
      expect(agent.id).toBeDefined();
      expect(agent.name).toBeDefined();
      expect(agent.description).toBeDefined();
      expect(agent.prompt).toBeDefined();
      expect(agent.isBuiltin).toBe(true);
      expect(agent.category).toBeDefined();
    });
  });
});

